package com.abso.mp3tunes.locker.ui;

import org.apache.commons.lang.StringUtils;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

import com.abso.mp3tunes.locker.core.AudioScrobblerServiceException;
import com.abso.mp3tunes.locker.core.LockerServiceException;
import com.abso.mp3tunes.locker.core.data.AudioScrobblerHandshakeData;
import com.abso.mp3tunes.locker.core.data.LoginData;
import com.abso.mp3tunes.locker.core.data.Track;
import com.abso.mp3tunes.locker.core.services.AbstractLockerService;
import com.abso.mp3tunes.locker.core.services.AudioScrobblerService;
import com.abso.mp3tunes.locker.core.services.AuthenticationService;
import com.abso.mp3tunes.locker.core.services.LockerService;
import com.abso.mp3tunes.locker.ui.views.MusicPlayerView;

/**
 * The activator class controls the plug-in life cycle
 */
public class LockerPlugin extends AbstractUIPlugin implements
		IPropertyChangeListener {

	/** The plug-in unique identifier. */
	public static final String PLUGIN_ID = "com.abso.mp3tunes.locker.ui";

	/** The MP3tunes partner token (registered for http://abso.freehostia.com). */
	private static final String MP3_TUNES_PARTNER_TOKEN = "2038362021";

	/** The shared instance. */
	private static LockerPlugin plugin;

	/** The current login data. */
	private LoginData loginData;

	/** Constructs a new plug-in. */
	public LockerPlugin() {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) throws Exception {
		super.start(context);
		plugin = this;
		getPreferenceStore().setDefault(ILockerConstants.PREF_TIMEOUT,
				AbstractLockerService.DEFAULT_TIMEOUT);
		getPreferenceStore().setDefault(ILockerConstants.PREF_CHUNK_SIZE,
				LockerService.DEFAULT_CHUNK_SIZE);
		getPreferenceStore().setDefault(
				ILockerConstants.PREF_MAX_SEARCH_RESULTS,
				LockerService.DEFAULT_MAX_SEARCH_RESULTS);
		getPreferenceStore().addPropertyChangeListener(this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeImageRegistry(org.eclipse.jface.resource.ImageRegistry)
	 */
	protected void initializeImageRegistry(ImageRegistry reg) {
		reg.put(LockerImages.ADD_TO_PLAYLIST.toString(),
				imageDescriptorFromPlugin(PLUGIN_ID,
						"icons/full/clcl16/add_to_playlist.gif"));
		reg.put(LockerImages.ALBUM.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/obj16/album_obj.gif"));
		reg.put(LockerImages.ARTIST.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/obj16/artist_obj.gif"));
		reg.put(LockerImages.ASX.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/clcl16/asx.gif"));
		reg.put(LockerImages.BROWSER.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/cview16/browser_nav.gif"));
		reg.put(LockerImages.COLLAPSE_ALL.toString(),
				imageDescriptorFromPlugin(PLUGIN_ID,
						"icons/full/clcl16/collapseall.gif"));
		reg.put(LockerImages.LAST_FM.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/clcl16/last_fm.gif"));
		reg.put(LockerImages.M3U.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/clcl16/m3u.gif"));
		reg.put(LockerImages.NEXT_TRACK.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/cview16/next_track.gif"));
		reg.put(LockerImages.PAUSE_TRACK.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/cview16/pause_track.gif"));
		reg.put(LockerImages.PENDING.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/cview16/pending.gif"));
		reg.put(LockerImages.PLAY_TRACK.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/cview16/play_track.gif"));
		reg.put(LockerImages.PLAY.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/clcl16/play.gif"));
		reg.put(LockerImages.PLAYER.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/cview16/player_nav.gif"));
		reg.put(LockerImages.PLAYLIST.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/obj16/playlist_obj.gif"));
		reg.put(LockerImages.PREVIOUS_TRACK.toString(),
				imageDescriptorFromPlugin(PLUGIN_ID,
						"icons/full/cview16/previous_track.gif"));
		reg.put(LockerImages.REFRESH.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/clcl16/refresh.gif"));
		reg.put(LockerImages.REMOVE_FROM_PLAYLIST.toString(),
				imageDescriptorFromPlugin(PLUGIN_ID,
						"icons/full/clcl16/remove_from_playlist.gif"));
		reg.put(LockerImages.REPEAT.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/cview16/repeat.gif"));
		reg.put(LockerImages.SEARCH.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/clcl16/search.gif"));
		reg.put(LockerImages.SHUFFLE.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/cview16/shuffle.gif"));
		reg.put(LockerImages.STOP_TRACK.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/cview16/stop_track.gif"));
		reg.put(LockerImages.TRACK.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/obj16/track_obj.gif"));
		reg.put(LockerImages.XSPF.toString(), imageDescriptorFromPlugin(
				PLUGIN_ID, "icons/full/clcl16/xspf.gif"));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) throws Exception {
		getPreferenceStore().removePropertyChangeListener(this);
		plugin = null;
		super.stop(context);
	}

	/**
	 * Returns the shared instance.
	 * 
	 * @return the shared instance.
	 */
	public static LockerPlugin getDefault() {
		return plugin;
	}

	/**
	 * Returns the current login data, if the user is already logged in.
	 * Otherwise logs into the MP3tunes Locker service, and returns the new
	 * login data.
	 * 
	 * @return the login data.
	 * @throws LockerServiceException
	 *             if an exception occurred connecting to the authentication
	 *             service.
	 */
	public LoginData getLoginData() throws LockerServiceException {
		if (loginData == null) {
			synchronized (this) {
				if (loginData == null) {
					AuthenticationService authService = new AuthenticationService(
							MP3_TUNES_PARTNER_TOKEN);
					authService.setTimeout(getServiceTimeout());
					loginData = authService.login(getPreferenceStore()
							.getString(ILockerConstants.PREF_USERNAME),
							getPreferenceStore().getString(
									ILockerConstants.PREF_PASSWORD));
				}
			}
		}
		return loginData;
	}

	/** Resets the current login data. */
	public void resetLoginData() {
		loginData = null;
	}

	/**
	 * Returns the authentication service.
	 * 
	 * @return the authentication service.
	 * @throws LockerServiceException
	 */
	public AuthenticationService getAuthenticationService()
			throws LockerServiceException {
		AuthenticationService authService = new AuthenticationService(
				MP3_TUNES_PARTNER_TOKEN);
		authService.setTimeout(getServiceTimeout());
		return authService;
	}

	/**
	 * Returns the locker service.
	 * 
	 * @return the locker service.
	 * @throws LockerServiceException
	 */
	public LockerService getLockerService() throws LockerServiceException {
		LockerService service = new LockerService(MP3_TUNES_PARTNER_TOKEN,
				getLoginData());
		service.setTimeout(getServiceTimeout());
		service.setChunkSize(getChunkSize());
		return service;
	}

	/**
	 * Forces the music player view to be shown within the Eclipse workbench.
	 * 
	 * @return the music player view.
	 */
	public MusicPlayerView showMusicPlayer() {
		IWorkbenchWindow window = LockerPlugin.getDefault().getWorkbench()
				.getActiveWorkbenchWindow();
		IWorkbenchPage page = window.getActivePage();
		try {
			IViewPart musicPlayer = page.showView(
					ILockerConstants.ID_MUSIC_PLAYER_VIEW, null,
					IWorkbenchPage.VIEW_VISIBLE);
			return (MusicPlayerView) musicPlayer;
		} catch (PartInitException e) {
			return null;
		}
	}

	/**
	 * Gets the active workbench window.
	 * 
	 * @return the active workbench window.
	 */
	public static final IWorkbenchWindow getActiveWorkbenchWindow() {
		return getDefault().getWorkbench().getActiveWorkbenchWindow();
	}

	/**
	 * Gets the active workbench shell.
	 * 
	 * @return the active workbench shell.
	 */
	public static final Shell getActiveWorkbenchShell() {
		IWorkbenchWindow window = getActiveWorkbenchWindow();
		if (window == null) {
			return null;
		}
		return window.getShell();
	}

	/**
	 * Gets the active workbench page.
	 * 
	 * @return the active workbench page.
	 */
	public static final IWorkbenchPage getActiveWorkbenchPage() {
		IWorkbenchWindow window = getActiveWorkbenchWindow();
		if (window == null) {
			return null;
		}
		return window.getActivePage();
	}

	/**
	 * Returns the connection time-out to use on Locker connections.
	 * 
	 * @return the connection time-out.
	 */
	private int getServiceTimeout() {
		int timeout = getPreferenceStore()
				.getInt(ILockerConstants.PREF_TIMEOUT);
		return timeout > 0 ? timeout : AbstractLockerService.DEFAULT_TIMEOUT;
	}

	/**
	 * Returns the chunk size used to break up request to avoid connection
	 * time-outs for large Lockers.
	 * 
	 * @return the chunk size.
	 */
	private int getChunkSize() {
		int chunkSize = getPreferenceStore().getInt(
				ILockerConstants.PREF_CHUNK_SIZE);
		return chunkSize > 0 ? chunkSize : LockerService.DEFAULT_CHUNK_SIZE;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
	 */
	public void propertyChange(PropertyChangeEvent event) {
		if (ILockerConstants.PREF_USERNAME.equals(event.getProperty())
				|| (ILockerConstants.PREF_PASSWORD.equals(event.getProperty()))) {
			loginData = null;
		}
	}

	/**
	 * Notifies to the AudioScrobbler service that a track has been played.
	 * This method does nothing if the Last.fm preferences are not set.
	 * 
	 * @param track
	 *            the played track.
	 */
	public void submitToAudioScrobbler(Track track) {
		String lastFmUsername = getPreferenceStore().getString(
				IAudioScrobblerConstants.PREF_USERNAME);
		String lastFmPassword = getPreferenceStore().getString(
				IAudioScrobblerConstants.PREF_PASSWORD);
		if (!StringUtils.isBlank(lastFmUsername)
				&& !StringUtils.isBlank(lastFmPassword)) {
			AudioScrobblerService service = new AudioScrobblerService();
			try {
				AudioScrobblerHandshakeData handshakeData = service.handshake(
						lastFmUsername, lastFmPassword);
				service.submit(handshakeData, track);
			} catch (AudioScrobblerServiceException e) {
				e.printStackTrace();
			}
		}
	}


}
